package testapp.client;

import java.util.logging.Logger;

import testapp.client.animation.AnimationCallbackPart;
import testapp.client.animation.CompositeAnimationFrame;
import testapp.client.handler.FinishEditHandler;
import testapp.client.handler.StartEditHandler;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.TouchEndEvent;
import com.google.gwt.event.dom.client.TouchEndHandler;
import com.google.gwt.event.dom.client.TouchMoveEvent;
import com.google.gwt.event.dom.client.TouchMoveHandler;
import com.google.gwt.event.dom.client.TouchStartEvent;
import com.google.gwt.event.dom.client.TouchStartHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Widget;

public class NotesPanel extends Composite {
    private Logger logger = Logger.getLogger("main");

    interface MyUiBinder extends UiBinder<Widget, NotesPanel> {}

    private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);

    @UiField FlowPanel delegate;

    private int lastStartPosY;
    private int lastLastStartPosY;

    private long lastStartTimeY;
    private long lastLastStartTimeY;

    private int scrollY;

    private boolean locked;

    private Note editableNote;

    public NotesPanel() {
        initWidget(uiBinder.createAndBindUi(this));

        CompositeAnimationFrame.getInstance().addAnimationCallbackPart(new AnimationCallbackPart() {
            @Override
            public void execute() {
                NotesPanel.this.getElement().getStyle().setProperty("webkitTransform", "translateY(" + scrollY + "px)");
            }
        });

        delegate.addDomHandler(new TouchStartHandler() {
            @Override
            public void onTouchStart(TouchStartEvent event) {
                if (!locked) {
                    lastStartPosY = event.getTouches().get(0).getPageY();
                    lastLastStartPosY = lastStartPosY;

                    lastStartTimeY = System.currentTimeMillis();
                    lastLastStartTimeY = lastStartTimeY;

                    delegate.getElement().getStyle().setProperty("webkitTransition", "-webkit-transform 0s linear");
                }
            }
        }, TouchStartEvent.getType());

        delegate.addDomHandler(new TouchMoveHandler() {
            @Override
            public void onTouchMove(TouchMoveEvent event) {
                if (!locked) {
                    int deltaY = event.getTouches().get(0).getPageY() - lastStartPosY;

                    lastLastStartPosY = lastStartPosY;
                    lastStartPosY = event.getTouches().get(0).getPageY();

                    lastLastStartTimeY = lastStartTimeY;
                    lastStartTimeY = System.currentTimeMillis();

                    scrollY += deltaY;

                    if (scrollY > 0) scrollY = 0;
                    if (scrollY < getMinScrollY()) scrollY = getMinScrollY();

                    event.preventDefault();
                }
            }
        }, TouchMoveEvent.getType());

        delegate.addDomHandler(new TouchEndHandler() {
            @Override
            public void onTouchEnd(TouchEndEvent event) {
                if (!locked) {
                    int deltaY = lastStartPosY - lastLastStartPosY;

                    long time = lastStartTimeY - lastLastStartTimeY;

                    if (time != 0) {
                        double speed = (double) deltaY / time;

                        scrollY += (int) (speed * 10);

                        delegate.getElement().getStyle().setProperty("webkitTransition", "-webkit-transform 0.3s ease-out");

                        if (scrollY > 0) scrollY = 0;
                        if (scrollY < getMinScrollY()) scrollY = getMinScrollY();
                    }
                }
            }
        }, TouchEndEvent.getType());

        Window.addResizeHandler(new ResizeHandler() {
            @Override
            public void onResize(ResizeEvent event) {
                if (locked) {
                    int offsetBottom = (editableNote.getElement().getOffsetTop() + scrollY) + editableNote.getOffsetHeight();

                    if (event.getHeight() < offsetBottom) {
                        delegate.getElement().getStyle().setProperty("webkitTransition", "-webkit-transform 0.5s ease-out");

                        setScrollY(scrollY - (offsetBottom - event.getHeight()));
                    }
                }
            }
        });
    }

    public Note addNote(String text) {
        Note note = new Note(text);

        note.addStartEditHandler(new StartEditHandler() {
            @Override
            public void onStartEdit(Note note) {
                editableNote = note;

                setLocked(true);
            }
        });

        note.addFinishEditHandler(new FinishEditHandler() {
            @Override
            public void onFinishEdit(Note note) {
                setLocked(false);
            }
        });

        delegate.add(note);

        return note;
    }

    private int getMinScrollY() {
        int parentHeight = NotesPanel.this.getParent().getOffsetHeight();

        int result = parentHeight - delegate.getOffsetHeight();

        return result > 0 ? 0 : result;
    }

    public FlowPanel getDelegate() {
        return delegate;
    }

    public int getScrollY() {
        return scrollY;
    }

    public void setScrollY(int scrollY) {
        this.scrollY = scrollY;
    }

    public void setLocked(boolean locked) {
        this.locked = locked;
    }
}
